package GA.population;

import java.util.ArrayList;
import java.util.List;

import abstractGA.chrom.Chrom;
import abstractGA.popu.Population;

/**
 * 单目标GA的种群
 * 
 * @author nyc
 * 
 */
public class GAPopu extends Population {

	public GAPopu() {
		super();
	}

	/**
	 * 获取最优染色体
	 */
	@Override
	public List<Chrom> getBestChroms() {
		if (bestChroms.size() == 0) {
			float bestFitness = Float.NEGATIVE_INFINITY;
			Chrom bestChrom = null;
			for (Chrom chrom : chroms) {
				float afResTime = ((Float) chrom.getObjVals().get(0))
						.floatValue();
				float curFitness = 1.0f / afResTime;
				if (Float.compare(curFitness, bestFitness) > 0) {
					bestFitness = curFitness;
					bestChrom = chrom;
				}
			}
			if (bestChrom != null) {
				bestChroms.add(bestChrom.copy());
			}
		}
		return bestChroms;
	}

	/**
	 * 轮盘赌选择
	 * 
	 * @param chroms
	 *            ：染色体集
	 * @param size
	 *            ：选出个体的个数
	 * @return：被选中染色体的下标数组
	 */
	public int[] rouletteWheelChoose(List<Chrom> chroms, int size) {
		int popSize = chroms.size();
		float fitnesses[] = new float[popSize];
		int i = 0;
		for (Chrom chrom : chroms) {
			float afResTime = ((Float) chrom.getObjVals().get(0)).floatValue();
			fitnesses[i] = 1.0f / afResTime;
			i++;
		}
		// 计算适应度的总和
		float fitnessSum = 0;
		for (int j = 0; j < popSize; j++) {
			fitnessSum += fitnesses[j];
		}
		// 计算每个个体适应度占总适应和的比例
		float[] weights = new float[popSize];
		for (int k = 0; k < popSize; k++) {
			weights[k] = (fitnesses[k] * 1.0f) / fitnessSum;
		}

		return rouletteWheelChoose(weights, size);
	}

	/**
	 * 交配选择
	 * 
	 * @param chroms
	 *            :染色体集合
	 * @param 返回
	 *            ：选中染色体下标的数组
	 */
	@Override
	public int[] mutingChoose(List<Chrom> chroms) {
		int popSize = chroms.size();
		if (popSize <= 0) {
			throw new ArrayIndexOutOfBoundsException();
		}
		int chosenIdxs[] = new int[popSize];
		int bestIdx = -1;
		float bestFitness = Float.MIN_VALUE;
		for (int i = 0; i < popSize; i++) {
			Chrom chrom = chroms.get(i);
			float afResTime = ((Float) chrom.getObjVals().get(0)).floatValue();
			float curFitness = 1.0f / afResTime;
			if (Float.compare(curFitness, bestFitness) > 0) {
				bestIdx = i;
				bestFitness = curFitness;
			}
		}

		chosenIdxs[0] = bestIdx;
		int tempIdxs[] = rouletteWheelChoose(chroms, popSize - 1);
		for (int j = 0; j < popSize - 1; j++) {
			chosenIdxs[j + 1] = tempIdxs[j];
		}
		return chosenIdxs;
	}

	/**
	 * 环境选择
	 * 
	 * @param tempPopu
	 *            ：临时种群
	 * @return：环境选择后的种群
	 */
	@Override
	public Population envSelect(Population tempPopu) {

		Population nxtPopu = copy();
		List<Chrom> nxtChroms = new ArrayList<Chrom>();
		Chrom curBestChrom = getBestChroms().get(0);
		Chrom tempBestChrom = tempPopu.getBestChroms().get(0);
		Chrom bestChrom = null;
		float curAfResTime = ((Float) curBestChrom.getObjVals().get(0))
				.floatValue();
		float curBestFitness = 1f / curAfResTime;
		float tempAfResTime = ((Float) tempBestChrom.getObjVals().get(0))
				.floatValue();
		float tempBestFitness = 1f / tempAfResTime;
		if (Float.compare(curBestFitness, tempBestFitness) > 0) {
			bestChrom = curBestChrom;
		} else {
			bestChrom = tempBestChrom;
		}
		nxtChroms.add(bestChrom.copy());
		nxtPopu.add(tempPopu.getChroms());

		int size = getChroms().size() - 1;
		int[] chosenIdxes = rouletteWheelChoose(nxtPopu.getChroms(), size);
		for (int j = 0; j < chosenIdxes.length; j++) {
			nxtChroms.add(nxtPopu.getChroms().get(chosenIdxes[j]).copy());
			// nxtChroms.add(nxtPopu.getChroms().get(j).copy());
		}
		nxtPopu.setChroms(nxtChroms);
		nxtPopu.getBestChroms().clear();
		return nxtPopu;
	}

	// 种群复制
	@Override
	public Population copy() {
		Population newPopu = new GAPopu();
		List<Chrom> newBestChroms = new ArrayList<Chrom>();
		for (Chrom bestChrom : bestChroms) {
			newBestChroms.add(bestChrom.copy());
		}
		newPopu.setBestChroms(newBestChroms);
		// 复制种群中的染色体
		for (int i = 0; i < chroms.size(); i++) {
			Chrom tmpChrom = chroms.get(i);
			newPopu.getChroms().add(tmpChrom.copy());
		}
		newPopu.setRandom(random);

		newPopu.setParameter(parameter);
		return newPopu;
	}

}
